﻿// Copyright (c) 2012 Mokah Nnamezie & Andrew Cooper
// Neo4Net graph database - http://neo4net.codeplex.com
//
// This file is part of Neo4Net - a .Net port of the Neo4j graph database
//
// Neo4Net is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace Neo4Net.Helpers
{
    using System;
    using NUnit.Framework;

    [TestFixture]
    public class TestFormat
    {
        [Test]
        public void TestDateTime()
        {
            // Date
            long timeWithDate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            string dateAsString = Format.Date(timeWithDate);
            Assert.That(DateTime.Parse(dateAsString).Ticks / TimeSpan.TicksPerMillisecond, Is.EqualTo(timeWithDate));

            // Time
            string timeAsString = Format.Time(timeWithDate);
            Assert.That(TranslateToDate(timeWithDate, DateTime.Parse(timeAsString).Ticks / TimeSpan.TicksPerMillisecond, Format.DefaultTimeZone), Is.EqualTo(timeWithDate));
        }

        [Test]
        public void TestDateTimeWithTimeZone()
        {
            string zoneOffset = "+03:00";
            TimeSpan zoneOffsetSpan = TimeSpan.ParseExact(zoneOffset, @"\+hh\:mm", null);
            TimeZoneInfo zone = TimeZoneInfo.CreateCustomTimeZone("GMT" + zoneOffset, TimeSpan.ParseExact(zoneOffset, @"\+hh\:mm", null), "", "");

            // Date
            String asString = Format.Date(zone);
            Assert.That(asString.EndsWith(WithoutColon(zoneOffset)), Is.True);
            long timeWithDate = DateTime.Parse(asString).Ticks / TimeSpan.TicksPerMillisecond;

            asString = Format.Date(timeWithDate, zone);
            Assert.That(asString.EndsWith(WithoutColon(zoneOffset)), Is.True);
            Assert.That(DateTime.Parse(asString).Ticks / TimeSpan.TicksPerMillisecond, Is.EqualTo(timeWithDate));

            asString = Format.Date(new DateTime(timeWithDate * TimeSpan.TicksPerMillisecond), zone);
            Assert.That(asString.EndsWith(WithoutColon(zoneOffset)), Is.True);
            Assert.That(DateTime.Parse(asString).Ticks / TimeSpan.TicksPerMillisecond, Is.EqualTo(timeWithDate));

            // Time
            asString = Format.Time(timeWithDate, zone);
            Assert.That(DateTime.Parse(asString).Ticks / TimeSpan.TicksPerMillisecond, Is.EqualTo(timeWithDate));
            Assert.That(TranslateToDate(timeWithDate, DateTime.Parse(asString).Ticks / TimeSpan.TicksPerMillisecond, zone), Is.EqualTo(timeWithDate));

            asString = Format.Time(new DateTime(timeWithDate * TimeSpan.TicksPerMillisecond), zone);
            Assert.That(TranslateToDate(timeWithDate, DateTime.Parse(asString).Ticks / TimeSpan.TicksPerMillisecond, zone), Is.EqualTo(timeWithDate));
        }

        private long TranslateToDate(long timeWithDate, long time, TimeZoneInfo timeIsGivenInThisTimeZone)
        {
            DateTimeOffset dateTime = new DateTimeOffset(new DateTime(timeWithDate * TimeSpan.TicksPerMillisecond), timeIsGivenInThisTimeZone.BaseUtcOffset);

            DateTime timeOnly = new DateTime(time * TimeSpan.TicksPerMillisecond);
            var crossedDayBoundary = timeIsGivenInThisTimeZone.BaseUtcOffset != Format.DefaultTimeZone.BaseUtcOffset && timeOnly.Hour < dateTime.Hour;

            var timeDate = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, timeOnly.Hour, timeOnly.Minute, timeOnly.Second, timeOnly.Millisecond);

            return new DateTimeOffset(timeDate, timeIsGivenInThisTimeZone.BaseUtcOffset)
                .AddDays(crossedDayBoundary ? 1 : 0)
                .Ticks / TimeSpan.TicksPerMillisecond;
        }

        private string WithoutColon(string zoneOffset)
        {
            return zoneOffset.Replace(":", "");
        }
    }
}
